# -*- coding: UTF-8 -*-

import os
import sys

import gconf
import gtk
import pango

from observer import Observee

class Setting(Observee):

    class ParseError(Exception):
        pass

    def __init__(self, client, key, name, default):
        super(Setting, self).__init__()

        self.client = client
        self.entry = '%s/%s' % (key, name)
        self.default = default

        self.client.notify_add(self.entry, lambda a,b,c,d: self.__value_changed(c.value))
        self.__value_changed(self.client.get_without_default(self.entry))

    def __value_changed(self, value):
        if value is None:
            self.__value = self.default
        else:
            try:
                self.__value = self._parse_gconf_value(value)
            except self.ParseError:
                self.__value = self.default
        self.notify()

    def _parse_gconf_value(value):
        raise NotImplementedError('')

    def value(self):
        return self.__value


class BooleanSetting(Setting):

    def __init__(self, client, key, name, default=False):
        super(BooleanSetting, self).__init__(client, key, name, default)

    def _parse_gconf_value(self, value):
        if value.type != gconf.VALUE_BOOL:
            raise self.ParseError()
        return value.get_bool()

    def set(self, value):
        self.client.set_bool(self.entry, value)


class InvertedBooleanSetting(BooleanSetting):

    def __init__(self, client, key, name, default=True):
        super(InvertedBooleanSetting, self).__init__(client, key, name, default)

    def _parse_gconf_value(self, value):
        return not super(InvertedBooleanSetting, self)._parse_gconf_value(value)

    def set(self, value):
        return super(InvertedBooleanSetting, self).set(not value)


class IntegerSetting(Setting):

    def __init__(self, client, key, name, default, min=-sys.maxint-1, max=sys.maxint):
        self.min, self.max = (min, max)
        super(IntegerSetting, self).__init__(client, key, name, default)

    def _parse_gconf_value(self, value):
        if value.type != gconf.VALUE_INT:
            raise self.ParseError()
        v = value.get_int()
        if v < self.min: v = self.min
        if v > self.max: v = self.max
        return v

    def set(self, value):
        self.client.set_int(self.entry, value)


class StringSetting(Setting):

    def _parse_gconf_value(self, value):
        if value.type != gconf.VALUE_STRING:
            raise self.ParseError()
        return value.get_string()

    def set(self, value):
        self.client.set_string(self.entry, value)


class ColorSetting(StringSetting):

    def __init__(self, client, key, name, default):
        default = gtk.gdk.color_parse(default)
        super(ColorSetting, self).__init__(client, key, name, default)

    def _parse_gconf_value(self, value):
        value = super(ColorSetting, self)._parse_gconf_value(value)
        try:
            return gtk.gdk.color_parse(value)
        except:
            raise self.ParseError()

    def set(self, value):
        return super(ColorSetting, self).set(value.to_string())


class FontSetting(StringSetting):

    def __init__(self, client, key, name):
        super(FontSetting, self).__init__(client, key, name, default=(None, None))

    def _parse_gconf_value(self, value):
        font_name = super(FontSetting, self)._parse_gconf_value(value)
        font = pango.FontDescription(font_name)
        return (font_name, font)

    def value(self):
        raise NotImplemented()

    def font_name(self):
        return super(FontSetting, self).value()[0]

    def font(self):
        return super(FontSetting, self).value()[1]

    def set(self, value):
        raise NotImplemented()

    def set_font_name(self, font_name):
        return super(FontSetting, self).set(font_name)


class CustomFontSetting(Observee):

    def __init__(self, client, key, name, default):
        super(CustomFontSetting, self).__init__()
        self.default = default

        self.var_custom = BooleanSetting(client, key, name + 'IsCustom')
        self.var_custom.attach(lambda setting: self.notify())

        def fontChanged(setting):
            if setting.font() is None:
                self.set_custom(False)
            else:
                self.notify()
        self.var_font = FontSetting(client, key, name)
        self.var_font.attach(fontChanged)

    def is_custom(self):
        return self.var_custom.value()

    def set_custom(self, value):
        return self.var_custom.set(value)

    def font(self):
        return self.var_font.font() if self.is_custom() else None

    def font_name(self):
        font_name = self.var_font.font_name()
        return font_name if font_name is not None else self.default

    def set_font_name(self, value):
        return self.var_font.set_font_name(value)

# ---

class GConfClient(object):

    def __init__(self, key):
        super(GConfClient, self).__init__()
        client = gconf.client_get_default()
        key = key

        self.nick = StringSetting(client, key, 'nick', default='mrShadow')
        self.refreshInterval = IntegerSetting(client, key, 'refreshInterval', default=5, min=1, max=100)

        self.layoutInRow = InvertedBooleanSetting(client, key, 'layoutStacked')
        self.textIsAlwaysHorizontal = BooleanSetting(client, key, 'textIsAlwaysHorizontal')
        self.showRating = InvertedBooleanSetting(client, key, 'showRating')

        self.karmaTextColor = ColorSetting(client, key, 'karmaTextColor', default='#74C262')
        self.habrapowerTextColor = ColorSetting(client, key, 'habrapowerTextColor', default='#25A8FF')
        self.ratingTextColor = ColorSetting(client, key, 'ratingTextColor', default='#777777')

        self.karmaFont = CustomFontSetting(client, key, 'karmaFont', default='Sans 9')
        self.ratingFont = CustomFontSetting(client, key, 'ratingFont', default='Sans 9')

            #
            # Check out 'http_proxy' environment variable first.
            # If it's undefined, look into GNOME proxy settings.
            #
            # Note that urllib2 checks 'http_proxy' itself, we need it just to
            # 1. determine whether to read GNOME settings...
            # 2. ...and display the used proxy in the preferences dialog.
            #
        self.http_proxy = os.environ.get('http_proxy', None)
        if self.http_proxy is None:
            if client.get('/system/http_proxy/use_http_proxy').get_bool():
                auth = ''
                if client.get('/system/http_proxy/use_authentication').get_bool():
                    auth = '%s:%s' % (
                        client.get('/system/http_proxy/authentication_user').get_string(),
                        client.get('/system/http_proxy/authentication_password').get_string())
                addr = '%s:%d' % (
                    client.get('/system/http_proxy/host').get_string(),
                    client.get('/system/http_proxy/port').get_int())
                self.http_proxy = 'http://%s%s%s' % (
                    auth,
                    '@' if auth else '',
                    addr)
